package proxy

import (
	"go-proxy/common"
	"go-proxy/config"
	"go-proxy/proxy/auth"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
)

type TransProxy struct {
	server *config.ProxyServer
}

func (t *TransProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	common.LogTrace("TransProxy ServeHTTP path:", r.URL.Path)
	common.LogTrace("TransProxy ServeHTTP host:", r.Host)
	server := t.server

	// 健康检查
	if serverHealthCheck(r) {
		w.WriteHeader(http.StatusOK)
		return
	}

	common.AccessReqLogInfo(r, "http request")

	// 添加前置监控指标
	HandleServerBeforeMetrics(server)
	IncApiRequestTotal(server, r)
	AddUploadBytes(r.ContentLength)

	// 匹配路由
	route, ok := matchRoute(server.Name, r)
	if !ok {
		common.AccessLogErrorf(r, "no route config server=%s", server.Name)
		w.WriteHeader(http.StatusNotFound)
		IncServerRequestCodeTotal(server, http.StatusNotFound)
		_, err := w.Write([]byte("no route config"))
		if err != nil {
			common.AccessLogErrorf(r, "write error server=%s err=%v", server.Name, err)
		}
		return
	}
	common.LogDebugF("route config:%s", route)

	if !auth.HandleAuth(w, r, route.AuthName) {
		common.AccessReqLogInfo(r, "auth failed server=%s router=%s", server.Name, route.Name)
		return
	}

	// 获取目标服务
	targetPath, err := getLoadBalance(route)
	if err != nil {
		common.AccessLogErrorf(r, "target register not found. server=%s err=%v", server.Name, err)
		w.WriteHeader(http.StatusNotFound)
		IncServerRequestCodeTotal(server, http.StatusNotFound)
		_, err := w.Write([]byte("no target register"))
		if err != nil {
			common.AccessLogErrorf(r, "write error server=%s err=%v", server.Name, err)
		}
		return
	}

	targetURL, err := url.Parse(targetPath)
	if err != nil {
		common.AccessLogErrorf(r, "parse targetPath error. server=%s error=%v", server.Name, err)
	}

	proxy := httputil.NewSingleHostReverseProxy(targetURL)

	// 自定义Director函数来修改请求
	originalDirector := proxy.Director
	proxy.Director = func(req *http.Request) {
		originalDirector(req)
		req.URL.Scheme = targetURL.Scheme
		req.URL.Host = targetURL.Host
		req.Host = targetURL.Host

		// 重写路由地址
		common.LogDebug("RewritePath before url:", req.URL.String())
		if len(route.RewritePath) > 0 {
			if route.RewritePath == "/" {
				req.URL.Path = strings.Replace(req.URL.Path, route.Path, "", 1)
			} else {
				req.URL.Path = strings.Replace(req.URL.Path, route.Path, route.RewritePath, 1)
			}
		}
		common.LogDebug("RewritePath after url:", req.URL.String())
	}

	handleResponse(server, proxy, w, r)
}
